package bb.lanxing.mvp.presetner;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;

import bb.lanxing.R;
import bb.lanxing.model.database.RouteBook;
import bb.lanxing.model.database.RouteBookPoint;
import bb.lanxing.model.database.RouteSlope;
import bb.lanxing.mvp.model.AltitudeModelImpl;
import bb.lanxing.mvp.model.RouteMapModelImpl;
import bb.lanxing.mvp.model.RouteSlopeModelImpl;
import bb.lanxing.mvp.model.i.IAltitudeModel;
import bb.lanxing.mvp.model.i.IRouteMapModel;
import bb.lanxing.mvp.model.i.IRouteSlopeModel;
import bb.lanxing.mvp.presetner.i.IRouteDetailPresenter;
import bb.lanxing.mvp.view.i.IRouteDetailView;
import bb.lanxing.util.DistanceUtil;
import bb.lanxing.util.RouteBookUtil;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

public class RouteBookDetailPresenterImpl extends BasePresenter implements IRouteDetailPresenter {
    private static final int ALTITUDE_POINT_SAMPLE = 1000;
    private List<RouteBookPoint> altitudePoints;
    private IRouteDetailView detailView;
    private IRouteMapModel routeMapModel = new RouteMapModelImpl();
    private IAltitudeModel altitudeModel = new AltitudeModelImpl();
    private IRouteSlopeModel slopeModel = new RouteSlopeModelImpl();

    public RouteBookDetailPresenterImpl(IRouteDetailView detailView) {
        this.detailView = detailView;
    }

    @Override
    public void loadRoute(long lushuId) {
        if (lushuId < 0) {
            this.detailView.toast(R.string.lushu_toast_no_lushu);
            this.detailView.exit();
        }
        this.routeMapModel.queryRoute(lushuId).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onNext(RouteBook routeBook) {
                if (routeBook == null) {
                    detailView.toast(R.string.lushu_toast_no_lushu);
                    detailView.exit();
                    return;
                }
                detailView.onLoadRoute(routeBook);
            }
        });
    }

    @Override
    public void loadRouteAltitude(final RouteBook routeBook) {
        Observable<List<RouteBookPoint>> flatMap;
        JSONArray altitudeJsonArray = routeBook.getAltitudeJsonArray();
        if (altitudeJsonArray == null) {
            if (routeBook.getServerId() > 0 && routeBook.getServerType() == 1) {
                flatMap = this.altitudeModel.requestLushuAltitudePoint(routeBook.getServerId(), 1000).map(lushuPoints -> {
                    routeBook.setAltitudeString(altitudeModel.saveAltitudePoints(routeBook.getId(), lushuPoints));
                    return lushuPoints;
                });
            } else {
                flatMap = Observable.just(routeBook).subscribeOn(Schedulers.io())
                        .flatMap(lushu2 -> altitudeModel.getSampleRoutePoint(lushu2.getId(), lushu2.getDistance()))
                        .flatMap(latLngs -> altitudeModel.requestPointAltitude(latLngs)).map(lushuPoints -> {
                            routeBook.setAltitudeString(altitudeModel.saveAltitudePoints(routeBook.getId(), lushuPoints));
                            return lushuPoints;
                        });
            }
        } else {
            flatMap = Observable.just(altitudeJsonArray).subscribeOn(Schedulers.io()).flatMap(jsonArray -> {
                try {
                    return Observable.just(RouteBookUtil.parseAltitudeData(jsonArray));
                } catch (JSONException e) {
                    return Observable.error(e);
                }
            });
        }
        addSubscription(
                flatMap.observeOn(Schedulers.computation()).map((Func1<List<RouteBookPoint>, List<Float>>) lushuPoints -> {
                    altitudePoints = lushuPoints;
                    int size = lushuPoints.size();
                    ArrayList<Float> arrayList = new ArrayList<>(size);
                    float f = 0.0f;
                    arrayList.add(0.0f);
                    for (int i = 1; i < size; i++) {
                        RouteBookPoint lushuPoint = lushuPoints.get(i - 1);
                        RouteBookPoint lushuPoint2 = lushuPoints.get(i);
                        f = (float) (f + DistanceUtil.get(lushuPoint.getLatitude(), lushuPoint.getLongitude(),
                                lushuPoint2.getLatitude(), lushuPoint2.getLongitude()));
                        arrayList.add(f);
                    }
                    float distance = (float) (routeBook.getDistance() / f);
                    for (int i2 = 0; i2 < arrayList.size(); i2++) {
                        arrayList.set(i2, (Float) arrayList.get(i2) * distance);
                    }
                    return arrayList;
                }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<>() {
                    @Override
                    public void onCompleted() {
                        detailView.dismissLoadingDialog();
                    }

                    @Override
                    public void onError(Throwable e) {
                        detailView.dismissLoadingDialog();
                        e.printStackTrace();
                    }

                    @Override
                    public void onNext(List<Float> distances) {
                        detailView.onLoadAltitudePoints(altitudePoints, distances);
                        loadRouteSlopes(routeBook.getId(), routeBook.getServerId());
                    }
                }));
    }

    public void loadRouteSlopes(long lushuId, final long serverId) {
        this.slopeModel.queryRouteSlope(lushuId).flatMap(routeSlopes -> {
            if (routeSlopes == null || routeSlopes.isEmpty()) {
                return slopeModel.requestRouteSlop(serverId, ALTITUDE_POINT_SAMPLE)
                        .flatMap(routeSlopes2 -> slopeModel.saveSlopes(routeSlopes2));
            }
            return Observable.just(routeSlopes);
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onNext(List<RouteSlope> slopes) {
                detailView.onLoadSlopes(slopes);
            }
        });
    }
}
